<template>
  <view style="position: relative">
    <view class="verify-image-out" v-show="showImage">
      <view
        class="verify-image-panel"
        :style="{
          width: props.imgSize.width + 'px',
          height: props.imgSize.height + 'px',
          'margin-bottom': vSpace + 'px',
        }"
      >
        <view
          class="verify-refresh icon-refresh"
          style="z-index: 3"
          @click="refresh"
          v-show="showRefresh"
        >
        </view>
        <image
          :src="pointBackImgBase"
          id="image"
          ref="canvas"
          style="width: 100%; height: 100%; display: block"
          @click="bindingClick ? canvasClick($event) : undefined"
        ></image>
        <view
          v-for="(tempPoint, index) in tempPoints"
          :key="index"
          class="point-area"
          :style="{
            'background-color': '#1abd6c',
            color: '#fff',
            'z-index': 9999,
            width: '20px',
            height: '20px',
            'text-align': 'center',
            'line-height': '20px',
            'border-radius': '50%',
            position: 'absolute',
            top: tempPoint.y - 10 + 'px',
            left: tempPoint.x - 10 + 'px',
          }"
        >
          {{ index + 1 }}
        </view>
      </view>
    </view>

    <view
      class="verify-bar-area"
      :style="{
        width: props.imgSize.width + 'px',
        color: barAreaColor,
        'border-color': barAreaBorderColor,
        'line-height': '40px',
      }"
    >
      <text class="verify-msg">{{ text }}</text>
    </view>
  </view>
</template>
<script setup lang="ts">
import { ref, reactive, nextTick, onMounted, getCurrentInstance } from "vue";
/**
 * VerifyPoints
 * @description 点选
 * */
import { aesEncrypt } from "./../utils/ase.js";
import { myRequest } from "../utils/request.js";
defineOptions({ name: "VerifyPoints" });
let emit = defineEmits(["success", "error"]);
const props = defineProps({
  captchaType: String,
  vSpace: {
    type: Number,
    default: 5,
  },
  imgSize: {
    type: Object,
    default: () => ({
      width: 310,
      height: 155,
    }),
  },
});
const secretKey = ref(""); // 后端返回的加密秘钥 字段
const checkNum = ref(3); //
const fontPos = ref([]); // 选中的坐标信息
const checkPosArr = ref([]); // 用户点击的坐标
const num = ref(1); // 点击的记数
const pointBackImgBase = ref(""); // 后端获取到的背景图片
const pointTextList = ref([]); // 后端返回的点击字体顺序
const backToken = ref(""); // 后端返回的token值

const showImage = ref(true);
const tempPoints = ref([]);
const text = ref("");
const barAreaColor = ref("#fff");
const barAreaBorderColor = ref("#fff");
const showRefresh = ref(true);
const bindingClick = ref(true);
const imgLeft = ref(0);
const imgTop = ref(0);

function init() {
  // 加载页面
  fontPos.value.splice(0, fontPos.value.length);
  checkPosArr.value.splice(0, checkPosArr.value.length);
  num.value = 1;
  nextTick(() => {
    refresh();
  });
}

let canvas = ref(null);
const appInstance = getCurrentInstance().proxy;
function canvasClick(e) {
  const query = uni.createSelectorQuery().in(appInstance);
  query
    .select("#image")
    .boundingClientRect((rect) => {
      // @ts-ignore
      imgLeft.value = Math.ceil(rect.left);
      // @ts-ignore
      imgTop.value = Math.ceil(rect.top);
      checkPosArr.value.push(getMousePos(canvas.value, e));
      if (num.value == checkNum.value) {
        num.value = createPoint(getMousePos(canvas.value, e));
        //按比例转换坐标值
        checkPosArr.value = pointTransform(checkPosArr.value, props.imgSize);
        //等创建坐标执行完
        setTimeout(() => {
          //发送后端请求
          let info = {
            captchaType: props.captchaType,
            pointJson: secretKey.value
              ? aesEncrypt(JSON.stringify(checkPosArr.value), secretKey.value)
              : JSON.stringify(checkPosArr.value),
            token: backToken.value,
          };
          myRequest({
            url: `/captcha/check`,
            data: info,
            method: "POST",
          }).then((result) => {
            let res = result.data;
            if (res.repCode == "0000") {
              barAreaColor.value = "#4cae4c";
              barAreaBorderColor.value = "#5cb85c";
              text.value = "验证成功";
              bindingClick.value = false;
              setTimeout(() => {
                refresh();
              }, 1500);
              emit("success", {
                ...info,
              });
            } else {
              emit("error");
              barAreaColor.value = "#d9534f";
              barAreaBorderColor.value = "#d9534f";
              text.value = "验证失败";
              setTimeout(() => {
                refresh();
              }, 700);
            }
          });
        }, 400);
      }
      if (num.value < checkNum.value) {
        num.value = createPoint(getMousePos(canvas.value, e));
      }
    })
    .exec();
}

function getMousePos(obj, e) {
  let position = {
    x: Math.ceil(e.detail.x) - imgLeft.value,
    y: Math.ceil(e.detail.y) - imgTop.value,
  };
  return position;
}

function createPoint(pos) {
  tempPoints.value.push(Object.assign({}, pos));
  return ++num.value;
}

function refresh() {
  tempPoints.value.splice(0, tempPoints.value.length);
  barAreaColor.value = "#000";
  barAreaBorderColor.value = "#ddd";
  bindingClick.value = true;

  fontPos.value.splice(0, fontPos.value.length);
  checkPosArr.value.splice(0, checkPosArr.value.length);
  num.value = 1;

  getPicture();

  // text.value = '验证失败'
  showRefresh.value = true;
}

function getPicture() {
  let info = {
    captchaType: props.captchaType,
    ts: Date.now(), // 现在的时间戳
  };
  myRequest({
    url: "/captcha/get", //仅为示例，并非真实接口地址。
    data: info,
    method: "POST",
  }).then((result) => {
    let res = result.data;
    if (res.repCode == "0000") {
      pointBackImgBase.value =
        "data:image/png;base64," + res.repData.originalImageBase64;
      backToken.value = res.repData.token;
      secretKey.value = res.repData.secretKey;
      pointTextList.value = res.repData.wordList;
      text.value = "请依次点击【" + pointTextList.value.join(",") + "】";
    }
    // 判断接口请求次数是否失效
    if (res.repCode == "6201") {
      pointBackImgBase.value = null;
    }
  });
}
function pointTransform(pointArr, imgSize) {
  var newPointArr = pointArr.map((p) => {
    let x = Math.round((310 * p.x) / parseInt(imgSize.width));
    let y = Math.round((155 * p.y) / parseInt(imgSize.height));
    return {
      x,
      y,
    };
  });
  // console.log(newPointArr,"newPointArr");
  return newPointArr;
}
defineExpose({
  refresh,
});
onMounted(init);
</script>

<style scoped>
/*滑动验证码*/
.verify-bar-area {
  position: relative;
  background: #ffffff;
  text-align: center;
  -webkit-box-sizing: content-box;
  -moz-box-sizing: content-box;
  box-sizing: content-box;
  border: 1px solid #ddd;
}

.verify-bar-area .verify-move-block {
  position: absolute;
  top: 0px;
  left: 0;
  background: #fff;
  cursor: pointer;
  -webkit-box-sizing: content-box;
  -moz-box-sizing: content-box;
  box-sizing: content-box;
  box-shadow: 0 0 2px #888888;
}

.verify-bar-area .verify-move-block:hover {
  background-color: #337ab7;
  color: #ffffff;
}

.verify-bar-area .verify-left-bar {
  position: absolute;
  top: -1px;
  left: -1px;
  background: #f0fff0;
  cursor: pointer;
  -webkit-box-sizing: content-box;
  -moz-box-sizing: content-box;
  box-sizing: content-box;
  border: 1px solid #ddd;
}

.verify-image-panel {
  margin: 0;
  -webkit-box-sizing: content-box;
  -moz-box-sizing: content-box;
  box-sizing: content-box;
  border-top: 1px solid #ddd;
  border-bottom: 1px solid #ddd;
  border-radius: 3px;
  position: relative;
}

.verify-image-panel .verify-refresh {
  width: 25px;
  height: 25px;
  text-align: center;
  padding: 5px;
  cursor: pointer;
  position: absolute;
  top: 0;
  right: 0;
  z-index: 2;
}

.verify-image-panel .icon-refresh {
  font-size: 20px;
  color: #fff;
}

.verify-image-panel .verify-gap {
  background-color: #fff;
  position: relative;
  z-index: 2;
  border: 1px solid #fff;
}

.verify-bar-area .verify-move-block .verify-sub-block {
  position: absolute;
  text-align: center;
  z-index: 3;
  /* border: 1px solid #fff; */
}

.verify-bar-area .verify-move-block .verify-icon {
  font-size: 18px;
}

.verify-bar-area .verify-msg {
  z-index: 3;
}

.icon-refresh:before {
  content: " ";
  display: block;
  width: 16px;
  height: 16px;
  position: absolute;
  margin: auto;
  left: 0;
  right: 0;
  top: 0;
  bottom: 0;
  z-index: 9999;
  background-image: url("");
  background-size: contain;
}
</style>
